<script>
import { mapConstants } from '@/libs/constants'
import FilePicker from '@c/LzForm/FilePicker'
import LzTransfer from '@c/LzForm/LzTransfer'
import DynamicInput from '@c/LzForm/DynamicInput'
import _debounce from 'lodash/debounce'
import { nestedToSelectOptions } from '@/libs/utils'

export default {
  name: 'TypeInput',
  components: {
    FilePicker,
    LzTransfer,
    DynamicInput,
  },
  data() {
    return {
      filePickerKey: 1,
      localPlaceholder: this.placeholder,
    }
  },
  props: {
    type: String,
    value: undefined,
    label: null,
    placeholder:  {
      type: String,
      default: undefined,
    },
    options: Object,
    config_options: Object,
    form_disabled: {
      type: Boolean,
      default: false,
    },
  },
  computed: {
    ...mapConstants(['CONFIG_TYPES']),
    selectOptions() {
      let pairs = []
      let tempOptions = []
      if (
        this.type == this.CONFIG_TYPES.SINGLE || 
        this.type == this.CONFIG_TYPES.MULTIPLE
      ) {
        if (this.options.sample==1) {
          pairs = this.options.options.split('\n')
        } else if (this.options.sample==2 && this.config_options.options) {
          pairs = this.config_options.options.split('\n')
        } else if (this.options.sample==3 && this.config_options.options) {
          pairs = this.config_options.options.split('\n')
        }
        if (this.options.type=='transfer') {
          pairs.forEach((pair) => {
            const [key, title] = pair.split('=>').map((i) => i.trim())
            if (title) {
              tempOptions.push({ key, title })
            }
          })
        } else {
          pairs.forEach((pair) => {
            const [value, label] = pair.split('=>').map((i) => i.trim())
            if (label) {
              tempOptions.push({ value, label })
            }
          })
        }
        return tempOptions
      } else if (this.type == this.CONFIG_TYPES.CASCADER) {
        if (this.options.sample==1 && this.options.options) {
          tempOptions = JSON.parse(this.options.options)
        }
        if (this.options.sample==2 && this.config_options.options) {
          tempOptions = this.config_options.options
        }
        if (this.options.sample==4 && this.config_options.options) {
          tempOptions = this.config_options.options
        }
        return tempOptions
      } else if (this.type == this.CONFIG_TYPES.SELECT_TREE) {
        if (this.options.sample==1 && this.config_options.options) {
          pairs = nestedToSelectOptions(this.config_options.options, {
            id: 'value',
            title: 'label',
            node_string: 'node_string',
            children: 'children',
          }, false)
        } else if (this.options.sample==2 && this.config_options.options) {
          pairs = nestedToSelectOptions(this.config_options.options, {}, false)
        } else if (this.options.sample==4) {
          pairs = nestedToSelectOptions(this.config_options.options, {
            id: 'value',
            title: 'label',
            node_string: 'node_string',
            children: 'children',
          }, false)
        }
        pairs.forEach((pair) => {
          tempOptions.push({ 
            value:pair.id, 
            label:pair.title,
            text:pair.text,
          })
        })
        return tempOptions
      } else {
        return []
      }
    },
  },
  methods: {
    onInput(val,val2) {
      switch (this.type) {
        case this.CONFIG_TYPES.DATE:
        case this.CONFIG_TYPES.DATETIME:
        case this.CONFIG_TYPES.TIME:
          this.$emit('input', val2)
          break
        default:
          this.$emit('input', val)
      }
    },
    /**
     * 当类型或者文件选择最大限制改变时，要改变值的类型
     */
    initValue() {
      if (this.type === this.CONFIG_TYPES.FILE) {
        if (this.options.max > 1 && !Array.isArray(this.value)) {
          // 如果是多选，且原来的值不是数组，则用数组包起来，空值则为空数组
          this.onInput(this.value ? [this.value] : [])
        } else if (this.options.max <= 1 && Array.isArray(this.value)) {
          // 如果是单选，且原来的值是数组，则选第一个，否则为 null
          this.onInput(this.value[0] || null)
        }
      } else if (this.type === this.CONFIG_TYPES.SINGLE) {
        !this.value && this.onInput(undefined)
      } else if (this.type === this.CONFIG_TYPES.MULTIPLE) {
        !Array.isArray(this.value) && this.onInput([])
      } else if (this.type === this.CONFIG_TYPES.INPUT_JSON) {
        this.onInput(JSON.stringify(this.value, null, 4))
      } else if (this.type === this.CONFIG_TYPES.SELECT_TREE) {
        !this.value && this.onInput(undefined)
      } else if (this.type === this.CONFIG_TYPES.CASCADER) {
        this.onInput(this.value)
      } else {
        if (['string', 'boolean', 'number'].indexOf(typeof this.value) === -1) {
          this.onInput(null)
        }
      }
    },
    /**
     * 重新渲染 FilePicker 组件
     */
    updateFilePicker: _debounce(function () {
      this.filePickerKey++
    }, 500),
  },
  watch: {
    type: {
      handler() {
        this.initValue()
      },
      immediate: true,
    },
    'options.max'(newVal, oldVal) {
      // 如果变了之后，都还是多选，则不用更新
      // 这里条件取反
      if (!((newVal > 1) && (oldVal > 1))) {
        this.updateFilePicker()
      }
      this.initValue()
      // 多选时，如果数量变少了，则要去掉 value 中多出来的文件
      if ((newVal > 1) && (newVal < oldVal)) {
        this.onInput(this.value.slice(0, newVal))
      }
    },
    'options.ext'() {
      this.updateFilePicker()
    },
  },
  render(h) {
    const renderData = {
      attrs: {
        value: this.value,
      },
      on: {},
    }

    // v-model 的 event 的 key
    let vModelEventKey
    let component = null
    let slots = null
    const TYPES = this.CONFIG_TYPES
    switch (this.type) {
      case 'hidden':
        component = 'a-input'
        Object.assign(renderData.attrs, {
          type: 'hidden',
        })
        break
      case TYPES.INPUT:
      case TYPES.OTHER:
        component = 'a-input'
        vModelEventKey = 'change.value'
        Object.assign(renderData.attrs, {
          placeholder: this.localPlaceholder ?? '文本域',
        })
        break
      case TYPES.INPUT_JSON:
        component = 'a-input'
        vModelEventKey = 'change.value'
        renderData.attrs.type = 'textarea'
        renderData.attrs.autoSize =  {
          minRows: 2,
          maxRows: 10
        }
        break
      case TYPES.TEXTAREA:
        component = 'a-input'
        vModelEventKey = 'change.value'
        renderData.attrs.type = 'textarea'
        renderData.attrs.autoSize =  {
          minRows: 2,
          maxRows: 10
        }
        break
      case TYPES.FILE:
        component = 'file-picker'
        vModelEventKey = 'input'
        Object.assign(renderData.attrs, {
          max: this.options.max,
          ext: this.options.ext,
          multiple: this.options.max > 1,
          valueFields: "id,origin_filename,path",
          disabled: this.form_disabled
        })
        // 修改文件选择的配置时，通过更新 key，使重新渲染文件选择器，这样比较省事
        // 每次修改配置，使 key 加 1，并做 防抖处理
        renderData.key = this.filePickerKey
        break
      case TYPES.SINGLE:
      case TYPES.MULTIPLE: {
        const isMultiple = this.type === TYPES.MULTIPLE
        if (this.options.type === 'single_box' || this.options.type === 'multiple_box') {
          component = isMultiple
            ? 'a-checkbox-group'
            : 'a-radio-group'
          vModelEventKey = 'input'
          const optionComponent = isMultiple
            ? 'a-checkbox'
            : 'a-radio'
            slots = this.selectOptions.map((i) => (
            <optionComponent 
              key={i.value} 
              value={i.value}
            >
              {i.label}
            </optionComponent>
          ))
        } else if (this.options.type === 'single_select' || this.options.type === 'multiple_select') {
          component = 'a-select'
          vModelEventKey = 'change'
          if (!this.localPlaceholder) {
            this.localPlaceholder = isMultiple
            ? '多选下拉'
            : '单选下拉'
          }
          Object.assign(renderData.attrs, {
            mode: isMultiple ? 'multiple' : 'default',
            allowClear: true,
            showSearch: true,
            showArrow: true,
            optionFilterProp: "label",
            placeholder: this.localPlaceholder,
          })
          slots = this.selectOptions.map((i) => (
            <a-select-option 
              key={i.label} 
              value={i.value} 
              label={i.label}
            >
              {i.label}
            </a-select-option>
          ))
        } else if (this.options.type === 'transfer') {
          component = 'lz-transfer'
          vModelEventKey = 'change'
          if (this.options.sample == '2') {
            Object.assign(renderData.attrs, {
              dataSource:this.selectOptions,
              label:this.label,
              model:this.options.model
            })
          } else {
            Object.assign(renderData.attrs, {
              dataSource:this.selectOptions,
            })
          }
        }
        break
      }
      case TYPES.SELECT_TREE:
        component = 'a-select'
        vModelEventKey = 'change'
        Object.assign(renderData.attrs, {
          mode: 'default',
          allowClear: true,
          showSearch: true,
          optionFilterProp: "label",
          optionLabelProp: "label",
          placeholder: this.localPlaceholder ?? '树状下拉选择',
        })
        slots = this.selectOptions.map((i) => (
          <a-select-option 
            key={i.label} 
            value={i.value} 
            label={i.label}
          >
            {i.text}
          </a-select-option>
        ))
        break;
      case TYPES.EDITOR:
        component = 'editor'
        vModelEventKey = 'input'
        break
      case TYPES.DATE:
        component = 'a-date-picker'
        vModelEventKey = 'change'
        Object.assign(renderData.attrs, {
          placeholder: this.localPlaceholder ?? '日期选择',
          format: 'YYYY-MM-DD',
        })
        break
      case TYPES.TIME:
        component = 'a-time-picker'
        vModelEventKey = 'change'
        Object.assign(renderData.attrs, {
          placeholder: this.localPlaceholder ?? '时间选择',
          valueFormat: 'HH:mm',
          format: 'HH:mm'
        })
        break
      case TYPES.PASSWORD:
        component = 'a-input-password'
        vModelEventKey = 'change.value'
        Object.assign(renderData.attrs, {
          allowClear: true,
          placeholder: this.localPlaceholder ?? '密码框',
        })
        break;
      case TYPES.DATETIME:
        component = 'a-date-picker'
        vModelEventKey = 'change'
        Object.assign(renderData.attrs, {
          placeholder: this.localPlaceholder ?? '日期时间选择',
          format: 'YYYY-MM-DD HH:mm:ss',
          showTime: true,
        })
        break;
      case TYPES.DYNAMIC_INPUT:
        component = 'dynamic-input'
        vModelEventKey = 'input'
        break;
      case TYPES.DYNAMIC_TEXTAREA:
        component = 'dynamic-input'
        vModelEventKey = 'input'
        renderData.attrs.type = 'textarea'
        renderData.attrs.autoSize =  {
          minRows: 2,
          maxRows: 10
        }
        break;
      case TYPES.CASCADER:
        component = 'a-cascader'
        vModelEventKey = 'change'
        Object.assign(renderData.attrs, {
          placeholder: this.localPlaceholder ?? '级联选择',
          options: this.selectOptions
        });
        break;
      default:
        component = 'a-input'
        vModelEventKey = 'change.value'
        Object.assign(renderData.attrs, {
          placeholder: this.localPlaceholder ?? '文本域',
        })
        break
    }
    renderData.attrs.disabled = this.form_disabled
    renderData.on[vModelEventKey] = this.onInput
    return <component {...renderData}>{slots}</component>
  },
}
</script>
